// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

/// <summary>
/// Tests that the internal parameterless XElement ctor is not trimmed when used in an application that the IL Linker is run on.
/// The test simulates ILLink being run on the output of running sgen on an assembly that contains a simple POCO to be (de)serialized.
/// The POCO has a field of type XElement. The ctor is needed to deserialize into this type.
/// </summary>
public class Program
{
    public static int Main()
    {
        XmlReader xmlReader = CreateXmlReader();
        var serializer = new MyClassSerializer();

        // The line that tests that XElement ctor was preserved is in XmlSerializationReaderMyClass.Read2_MyClass.
        var obj = (MyClass)serializer.Deserialize(xmlReader);
        return obj.Element.Name == "MyElement" ? 100 : -1;
    }

    public static XmlReader CreateXmlReader()
    {
        string data =
            @"<?xml version=""1.0"" encoding=""utf-16""?>
            <MyClass xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
            <Element>
                <MyElement />
            </Element>
            </MyClass>";

        return XmlReader.Create(new MemoryStream(Encoding.Unicode.GetBytes(data)));
    }

    public class MyClass
    {
        public XElement Element;
    }

    // The following code was generated by sgen to (de)serialize the above class,
    // with slight modifications to remove the serialization logic that is unneeded in this test.

    public sealed class MyClassSerializer : XmlSerializer1
    {
        public override bool CanDeserialize(XmlReader xmlReader)
        {
            return xmlReader.IsStartElement("MyClass", "");
        }

        protected override void Serialize(object objectToSerialize, XmlSerializationWriter writer)
        {
            throw new NotImplementedException();
        }

        protected override object Deserialize(XmlSerializationReader reader)
        {
            return ((XmlSerializationReaderMyClass)(object)reader).Read3_MyClass();
        }
    }

    public abstract class XmlSerializer1 : XmlSerializer
    {
        protected override XmlSerializationReader CreateReader()
        {
            return (XmlSerializationReader)(object)new XmlSerializationReaderMyClass();
        }

        protected override XmlSerializationWriter CreateWriter()
        {
            throw new NotImplementedException();
        }
    }

    public class XmlSerializationReaderMyClass : XmlSerializationReader
    {
        private string id3_Element;

        private string id2_Item;

        private string id1_MyClass;

        public object Read3_MyClass()
        {
            object result = null;
            Reader.MoveToContent();
            if (Reader.NodeType == XmlNodeType.Element)
            {
                if ((object)Reader.LocalName != id1_MyClass || (object)Reader.NamespaceURI != id2_Item)
                {
                    throw CreateUnknownNodeException();
                }
                result = Read2_MyClass(isNullable: true, checkType: true);
            }
            else
            {
                UnknownNode((object)null, ":MyClass");
            }
            return result;
        }

        private MyClass Read2_MyClass(bool isNullable, bool checkType)
        {
            XmlQualifiedName xmlQualifiedName = checkType ? GetXsiType() : null;
            bool flag = false;
            if (isNullable)
            {
                flag = ReadNull();
            }
            if (checkType && !(xmlQualifiedName == null) && ((object)xmlQualifiedName.Name != id1_MyClass || (object)xmlQualifiedName.Namespace != id2_Item))
            {
                throw CreateUnknownTypeException(xmlQualifiedName);
            }
            if (flag)
            {
                return null;
            }
            MyClass myClass = new MyClass();
            bool[] array = new bool[1];
            while (Reader.MoveToNextAttribute())
            {
                if (!IsXmlnsAttribute(Reader.Name))
                {
                    UnknownNode((object)myClass);
                }
            }
            Reader.MoveToElement();
            if (Reader.IsEmptyElement)
            {
                Reader.Skip();
                return myClass;
            }
            Reader.ReadStartElement();
            Reader.MoveToContent();
            int num = 0;
            int readerCount = ReaderCount;
            while (Reader.NodeType != XmlNodeType.EndElement && Reader.NodeType != 0)
            {
                if (Reader.NodeType == XmlNodeType.Element)
                {
                    if (!array[0] && (object)Reader.LocalName == id3_Element && (object)Reader.NamespaceURI == id2_Item)
                    {
                        // This line would fail if the XElement ctor needed was trimmed out.
                        myClass.Element = (XElement)ReadSerializable((IXmlSerializable)Activator.CreateInstance(typeof(XElement), (BindingFlags)564, (Binder)null, new object[0], (CultureInfo)null), true);
                        array[0] = true;
                    }
                    else
                    {
                        UnknownNode((object)myClass, ":Element");
                    }
                }
                else
                {
                    UnknownNode((object)myClass, ":Element");
                }
                Reader.MoveToContent();
                CheckReaderCount(ref num, ref readerCount);
            }
            ReadEndElement();
            return myClass;
        }

        protected override void InitCallbacks()
        {
        }

        protected override void InitIDs()
        {
            id3_Element = Reader.NameTable.Add("Element");
            id2_Item = Reader.NameTable.Add("");
            id1_MyClass = Reader.NameTable.Add("MyClass");
        }

        public XmlSerializationReaderMyClass()
        {
        }
    }
}
